package com.xxx.system.service.impl;


import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.xxx.base.exception.BusinessException;
import com.xxx.dto.LoginDTO;
import com.xxx.jwt.JwtUtil;
import com.xxx.jwt.Payload;
import com.xxx.system.domain.Logininfo;
import com.xxx.system.domain.Menu;
import com.xxx.system.mapper.LogininfoMapper;
import com.xxx.system.mapper.MenuMapper;
import com.xxx.system.mapper.PermissionMapper;
import com.xxx.system.query.LogininfoQuery;
import com.xxx.system.service.ILogininfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 业务实现类: 登录信息Logininfo
 */
@Service
@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
public class LogininfoServiceImpl implements ILogininfoService {

    @Autowired
    private LogininfoMapper logininfoMapper;
    @Autowired
    private PermissionMapper permissionMapper;
    @Autowired
    private MenuMapper menuMapper;

    @Override
    public List<Logininfo> findAll() {
        return logininfoMapper.findAll();
    }

    @Override
    public Logininfo findOne(Long id) {
        return logininfoMapper.findOne(id);
    }

    @Override
    @Transactional
    public void delete(Long id) {
        //删除角色
        logininfoMapper.delete(id);
    }

    @Override
    @Transactional
    public void add(Logininfo logininfo) {
        //添加角色信息
        logininfoMapper.add(logininfo); //自增id
    }

    @Override
    @Transactional
    public void update(Logininfo logininfo) {
        logininfoMapper.update(logininfo);
    }

    @Override
    public void patchDelete(Long[] ids) {
        logininfoMapper.patchDelete(ids);
    }

    @Override
    public PageInfo<Logininfo> queryPage(LogininfoQuery logininfoQuery) {
        //1.开启分页
        PageHelper.startPage(logininfoQuery.getCurrentPage(), logininfoQuery.getPageSize());
        //a.查询总数量 - count()
        //b.会根据方言 mysql 自动实现分页查询,如果是mysql就会使用limit查询
        //c.自动计算limit的第一个参数: (currentPage-1)*pageSize
        //2.操作数据库
        List<Logininfo> data = logininfoMapper.queryPage(logininfoQuery);
        return new PageInfo<>(data);
    }


    @Override
    public String login(LoginDTO loginDTO) {


        //参数校验不能为空
        if (StrUtil.isBlank(loginDTO.getAccount()) ||
                StrUtil.isBlank(loginDTO.getPassword()) ||
                loginDTO.getType() == null) {
            throw new BusinessException("参数不能为空!!");
        }


        //对用户输入的用户名进行查询,看数据库中是否存在
        Logininfo logininfo = logininfoMapper.findByUsernameAndType(loginDTO);

        if (logininfo == null) {
            throw new BusinessException("账号不存在");
        }


        //对用户输入的密码进行加盐加密
        String passWordFromUser = SecureUtil.md5(loginDTO.getPassword() + logininfo.getSalt());
        if (!passWordFromUser.equals(logininfo.getPassword())) {
            throw new BusinessException("密码错误");
        }

        //判断账号状态
        if (!logininfo.getDisable()) {
            throw new BusinessException("当前账号已禁用，请联系管理员");
        }

        //查询权限信息
        List<String> perms = permissionMapper.findPermByLogininfoId(logininfo.getId());
        //查询菜单信息
        List<Menu> menus = menuMapper.findMenusByLogininfoId(logininfo.getId());

        List<Menu> menuTree = creatMenuTree(menus);


        //生成JWT字符串
        Payload payload = new Payload();
        payload.setPermissions(perms);
        payload.setMenus(menuTree);
        //登录信息脱敏
        logininfo.setSalt(null);
        logininfo.setPassword(null);
        payload.setLogininfo(logininfo);
        String jwtToken = JwtUtil.generateToken(payload);

        return jwtToken;
    }


    private static List<Menu> creatMenuTree(List<Menu> list) {
        //1.查询所有类型,redis取值
        //2.把所有list转换为map,id为key,自己为value
        Map<Long, Menu> menuMap =
                list.stream().collect(
                        Collectors.toMap(Menu::getId, (d) -> d)
                );
        //3.定义返回的typeTree集合
        List<Menu> menuTree = new ArrayList<Menu>();
        //4.找到顶层类型，没有上级类型就是顶级类型
        for (Menu menu : list) {
            //equals自己的id直接跳过，Long缓存问题，用equals

            //if (menu.getId().equals(id)) continue;

            if (menu.getParentId() == null) {
                menuTree.add(menu);
            } else {//非顶级类型加入到父级类型下
                //找到父类型
                Menu parentMenu = menuMap.get(menu.getParentId());
                //添加自己到父类型的子类型集合中
                parentMenu.getChildren().add(menu);
            }
        }
        return menuTree;
    }

}
